#include "ml307r.h"
#include "cJSON.h"
#include <stdlib.h>

#define DEBUG 1
#define ml307r_delay_ms delay1
#define ml307r_send_data Uart2_SendStr
#define ml307r_log_print printf

#define W_RX_BUFFER_SIZE 1024               // 数组缓存大小
uint8_t W_RxBuffer[W_RX_BUFFER_SIZE] = {0}; // 接收缓存数组
uint16_t W_RxDataCnt = 0;                   // 数组下标

#define WIFI_AGREEMENT "TCP"                                                                                       // 连接协议
#define SEVER_URL_IP "test123.fucku.top"                                                                           // 服务器IP
#define URL_TARGET_PORT "80"                                                                                       // 服务器端口
#define CONNECT_SERVER_INFO "AT+MIPOPEN=0,\"" WIFI_AGREEMENT "\",\"" SEVER_URL_IP "\"," URL_TARGET_PORT ",,1\r\n " // AT指令：连接服务器
#define DATA_TRANSPARTENT_MODE_INFO "AT+MIPMODE=0,1\r\n"                                                           // AT指令：透传模式

ML307R_TypeDef ML307R_Status = {1, 0, 0, 0};
ML307R_Data ML307R_Data_Info = {0.0, {0}, 0.0, {0}}; // 用于存储电费数据

const char building_map[16][6] = {"南1", "南2", "南3", "南4", "南5", "南6", "南7", "南8", "中1A", "中1B", "中1C", "中1D", "东20", "东21", "东22", "东23"}; // 楼号映射表
static uint8_t building_map_num = DEFAULT_BUILDING;                                                                                                        // 楼栋 通过索引得到
static uint8_t building_floor_num = DEFAULT_FLOOR;                                                                                                         // 楼层 如704 则填7
static uint8_t building_room_num = DEFAULT_ROOM;                                                                                                           // 楼层对应房间号 如704 则填4
static uint8_t limit_info = 1;

void delay1(uint16_t time)
{
    uint16_t i = 0;
    while (time--)
    {
        i = 10000; // 自己定义
        while (i--)
            ;
    }
}

static void Uart2_SendStr(char *str)
{
    HAL_UART_Transmit(&huart2, (uint8_t *)str, strlen(str), HAL_MAX_DELAY);
}

static void ml307r_clear_buffer(void)
{
    HAL_NVIC_DisableIRQ(USART2_IRQn); // 禁用USART2中断，防止清空时接收数据
    memset(W_RxBuffer, 0, sizeof(W_RxBuffer));
    W_RxDataCnt = 0;
    ML307R_Status.receiveDataFlag = 0; // 同步重置接收标志
    HAL_NVIC_EnableIRQ(USART2_IRQn);   // 重新使能中断
}
/**
 * @brief 用来将字符转为对应的 URL 编码形式
 *
 * @param str   原始字符串
 * @param encoded_str 编码后的字符串
 */

static void url_encode(const char *str, char *encoded_str)
{
    int i, j = 0;
    unsigned char c;

    for (i = 0; str[i] != '\0'; i++)
    {
        c = (unsigned char)str[i];

        // 如果是普通字符，不需要编码
        if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '~')
        {
            encoded_str[j++] = c;
        }
        else
        {
            // 将字符转换为 %XX 形式
            sprintf(encoded_str + j, "%%%02X", c);
            j += 3; // 每个字符占3个位置，例如 %E5
        }
    }
    encoded_str[j] = '\0'; // 结束符
}

uint8_t ch123 = 0;
static void ml307r_uart2_init(void)
{
    HAL_UART_Receive_IT(&huart2, &ch123, 1);
}
#if DEBUG == 1
#include "stdio.h"
typedef struct __FILE FILE;

int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}
#endif

static uint8_t ML307R_get_receive_flag(void)
{
    uint8_t flag = ML307R_Status.receiveDataFlag;
    ML307R_Status.receiveDataFlag = 0;
    return flag;
}

static uint8_t ml307r_send_command(char *cmd, char *res, uint8_t sendCount, uint16_t delay_xms, uint8_t printf_enable)
{
    if (printf_enable == W_ENABLE)
        ml307r_log_print("%s", cmd); // 这里可以打印每次发送的指令
    while (sendCount--)
    {
        ml307r_send_data(cmd);                 // AT指令发送
        ml307r_delay_ms(delay_xms);            // 适当增加点延迟，等待串口接收完成
        if (ML307R_get_receive_flag() == W_OK) // 如果串口接收到换行回车为结尾的数据
        {
            if (strstr((const char *)W_RxBuffer, res) != NULL) // 若找到关键字
            {
                ml307r_log_print("%s\r\n", res); // 这里可以打印每次发送的指令
                ml307r_clear_buffer();           // 清除数组
                return W_OK;                     // 退出，返回0-成功
            }
            ml307r_log_print("error %s\r\n", W_RxBuffer); // 没有找到关键字
            ml307r_clear_buffer();
        }
        ml307r_delay_ms(500);
    }
    return W_ERROR; // 返回1-失败
}

int ml307r_init(void)
{
    ml307r_uart2_init();
    ml307r_send_data("+++");
    ml307r_delay_ms(100);
    if (ml307r_send_command("AT+RESET\r\n", "OK", 3, 2000, W_ENABLE) != W_OK)
    {
        ml307r_log_print("AT error\r\n");
        ML307R_Status.error_code |= (1 << 0);
    }
    ml307r_delay_ms(2000);
    if (ml307r_send_command("AT\r\n", "OK", 3, 100, W_ENABLE) != W_OK)
    {
        ml307r_log_print("AT error\r\n");
        ML307R_Status.error_code |= (1 << 0);
    }
    if (ml307r_send_command("ATE0\r\n", "OK", 3, 100, W_ENABLE) != W_OK)
    {
        ml307r_log_print("ATE0 error\r\n");
        ML307R_Status.error_code |= (1 << 1);
    }
    if (ml307r_send_command("AT+CPIN?\r\n", "OK", 3, 100, W_ENABLE) != W_OK)
    {
        ml307r_log_print("AT+CPIN? error\r\n");
        ML307R_Status.error_code |= (1 << 2);
    }

    if (ml307r_send_command(CONNECT_SERVER_INFO, "CONNECT", 3, 2000, W_ENABLE) != W_OK)
    {
        ml307r_log_print("AT+MIPOPEN error\r\n");
        ML307R_Status.error_code |= (1 << 3);
        ML307R_Status.init_flag = 1;
        return 1; // 返回1-失败
    }
    ML307R_Status.init_flag = 0;
    return 0; // 返回0-成功
}

/**
 * @brief 通过cjson库获取电费数据
 * @note json数据格式如下
 * {
  "building": "南5",
  "current": {
    "remain": 56.15,
    "unit": "kWh",
    "update_time": "2025-08-10 20:25:00"
  },
  "records": [
    {
      "time": "2025-08-09 23:33",
      "usage": "12.85"
    }
  ],
  "room": "南5#704",
  "time": "2025-08-10 20:27:08"
}
 * @return uint8_t 0成功 1失败
 */
static uint8_t get_electricity_data(void)
{
    // ml307r_log_print("get_electricity_data\r\n");
    if (ML307R_get_receive_flag() == 0)
        return 1;
    char *json_data = NULL;
    // ml307r_log_print("W_RxBuffer:%s\r\n", W_RxBuffer);
    json_data = strchr((char *)W_RxBuffer, '{');
    // ml307r_log_print("json_data:%s\r\n", json_data);
    if (json_data != NULL)
    {
        cJSON *json_obj = cJSON_Parse(json_data);
        if (json_obj == NULL)
        {
            const char *error_ptr = cJSON_GetErrorPtr();
            if (error_ptr != NULL)
            {
                ml307r_log_print("Error before: %s\r\n", error_ptr);
            }
            return 1;
        }
        cJSON *current = cJSON_GetObjectItem(json_obj, "current");
        if (current != NULL)
        {
            cJSON *remain = cJSON_GetObjectItem(current, "remain");
            if (remain != NULL)
            {
                ML307R_Data_Info.remain = remain->valuedouble; // 获取剩余电量
                ml307r_log_print("remain: %.2f\r\n", ML307R_Data_Info.remain);
            }
            cJSON *update_time = cJSON_GetObjectItem(current, "update_time");
            if (update_time != NULL)
            {
                sprintf(ML307R_Data_Info.update_time, "%s", update_time->valuestring); // 获取更新时间
                ml307r_log_print("update_time: %s\r\n", ML307R_Data_Info.update_time);
            }
        }
        cJSON *records = cJSON_GetObjectItem(json_obj, "records");
        if (records != NULL)
        {
            cJSON *record = cJSON_GetArrayItem(records, 0);
            if (record != NULL)
            {
                cJSON *time = cJSON_GetObjectItem(record, "time");
                if (time != NULL)
                {
                    sprintf(ML307R_Data_Info.time, "%s", time->valuestring); // 获取时间
                    ml307r_log_print("time: %s\r\n", ML307R_Data_Info.time);
                }
                cJSON *usage = cJSON_GetObjectItem(record, "usage");
                if (usage != NULL)
                {
                    ML307R_Data_Info.usage = atof(usage->valuestring); // 获取用电量
                    ml307r_log_print("usageddd: %.2f\r\n", ML307R_Data_Info.usage);
                }
            }
        }
        cJSON_Delete(json_obj); // 释放内存
        return 0;
    }
    else
        return 1;
}
void ml307r_get_change_electricity(void)
{
    if (get_change_room_flag() == 0)
        return;
    ml307r_clear_buffer();
    char get_command[256] = {0}; // 用于存储GET请求命令
    if (ML307R_Status.error_code == 0x00)
    {
        char temp[10] = {0};
        uint16_t room_id = building_floor_num * 100 + building_room_num;
        // ml307r_log_print("Connecting to server...\r\n");
        url_encode(building_map[building_map_num], temp); // 编码楼号
        sprintf(get_command, "GET /electricity?building=%s&room=%d&limit=%d HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n\r\n", temp, room_id, limit_info, SEVER_URL_IP);
        // ml307r_log_print("%s", get_command);
    }
    ml307r_send_data(get_command);
    ml307r_delay_ms(1000);
    if (get_electricity_data() == 0)
    {
        set_change_room_flag(0);
    }
    // 清空接收缓冲区
    ml307r_clear_buffer();
}

void ml307r_get_electricity(void)
{
    if (ML307R_Status.start_flag == 0 || get_sleep_flag() == 1)
    {
        if (get_sleep_flag() == 1)
        {
            ml307r_log_print("---------------Sleeeping mode now!---------------\r\n");
            HAL_Delay(1500);
        }
        return;
    }
    ml307r_clear_buffer();
    char get_command[256] = {0}; // 用于存储GET请求命令
    if (ML307R_Status.error_code == 0x00)
    {
        char temp[10] = {0};
        uint16_t room_id = building_floor_num * 100 + building_room_num;
        // ml307r_log_print("Connecting to server...\r\n");
        url_encode(building_map[building_map_num], temp); // 编码楼号
        sprintf(get_command, "GET /electricity?building=%s&room=%d&limit=%d HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n\r\n", temp, room_id, limit_info, SEVER_URL_IP);
        // ml307r_log_print("%s", get_command);
    }
    ml307r_send_data(get_command);
    ml307r_delay_ms(1000);
    // ml307r_log_print("W_RxBuffer:%s\r\n", W_RxBuffer); // 这里可以打印每次发送的指令
    get_electricity_data();

    // 清空接收缓冲区
    ml307r_clear_buffer();
}

void set_ml307r_start_flag(uint8_t flag)
{
    ML307R_Status.start_flag = flag;
}

uint8_t ml307r_get_start_flag(void)
{
    return ML307R_Status.start_flag;
}
/**
 * @brief 获取初始化标志
 *
 * @return uint8_t 0则初始化成功 1则初始化失败
 */
uint8_t ml307r_get_init_flag(void)
{
    return ML307R_Status.init_flag;
}

float ml307r_get_remain(void)
{
    return ML307R_Data_Info.remain;
}
float ml307r_get_usage(void)
{
    return ML307R_Data_Info.usage;
}
char *ml307r_get_update_time(void)
{
    return ML307R_Data_Info.update_time;
}
char *ml307r_get_time(void)
{
    return ML307R_Data_Info.time;
}

static void ml307r_receive_callback(uint8_t byte)
{
    W_RxBuffer[W_RxDataCnt++] = byte;    // 接收数据转存
    if (W_RxDataCnt >= W_RX_BUFFER_SIZE) // 判断接收数据是否溢出
    {
        ml307r_clear_buffer();
    }
    if (W_RxDataCnt >= 2 && (W_RxBuffer[W_RxDataCnt - 2] == '\r' && W_RxBuffer[W_RxDataCnt - 1] == '\n')) // 判断结束位
    {
        ML307R_Status.receiveDataFlag = 1;
    }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART2)
    {
        ml307r_receive_callback(ch123);
        HAL_UART_Receive_IT(&huart2, &ch123, 1); // 再开启接收中断
    }
}

char *get_building_map_index(uint8_t index)
{
    if (index <= EAST_23)
        return (char *)building_map[index];
    else
        return NULL;
}
/**
 * @brief 获取楼栋号（去掉第一个中文字符）
 *
 * @return char*
 */
char *get_building_map_remain_index(uint8_t index)
{
    static char result[8];

    char *map = get_building_map_index(index);

    // 如果map为NULL，返回空字符串而不是NULL
    if (map == NULL)
    {
        result[0] = '\0'; // 清空结果
        return result;
    }

    size_t len = strlen(map);
    if (len <= 3)
    {
        result[0] = '\0'; // 清空结果
        return result;
    }

    // 将map字符串从索引3开始复制到result
    strcpy(result, map + 3);

    return result;
}

/**
 * @brief 获取楼栋号
 * @note 例如 南5
 * @param index
 * @return char*
 */
char *get_building_map(void)
{
    if (building_map_num < 16)
        return (char *)building_map[building_map_num];
    else
        return NULL;
}

/**
 * @brief 获取房间号
 *
 * @return uint16_t
 */
uint16_t get_building_room_num(void)
{
    return building_floor_num * 100 + building_room_num;
}
/**
 * @brief 获取楼栋号索引
 *
 * @return uint8_t
 */
uint8_t get_building_map_num(void)
{
    return building_map_num;
}
/**
 * @brief 设置楼栋号索引
 *
 * @param index
 */
void set_building_map_num(uint8_t index)
{
    building_map_num = index;
}
/**
 * @brief 设置楼层号
 *
 * @param floor
 */
void set_building_floor_num(uint8_t floor)
{
    building_floor_num = floor;
}
/**
 * @brief 设置房间号
 *
 * @param room
 */
void set_building_room_num(uint8_t room)
{
    building_room_num = room;
}
